﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Data;
using log4net;

namespace TsCore
{
    internal class UserHandler
    {
        private static UserHandler _instance;
        private List<TsUser> Users { get; set; }

        //Singleton
        public static UserHandler Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new UserHandler();
                }
                return _instance;
            }
        }

        public void CreateNewUser(string Name, String Surname, String UserName, String Password, String Email, string[] TsRoles)
        {
            MembershipCreateStatus createStatus;
            MembershipUser newUser = Membership.CreateUser(UserName, Password, Email, null, null, true, out createStatus);
            switch (createStatus)
            {
                case MembershipCreateStatus.Success:
                    break;
                case MembershipCreateStatus.DuplicateUserName:
                    throw new Exception(global::TsCore.Properties.Resources.DuplicateUserName);
                case MembershipCreateStatus.DuplicateEmail:
                    throw new Exception(createStatus.ToString());
                case MembershipCreateStatus.InvalidEmail:
                    throw new Exception(createStatus.ToString());
                default:
                   throw new Exception(createStatus.ToString());
            }
            Roles.AddUserToRoles(UserName, TsRoles);
            TsUser newTsUser = new TsUser(Name,Surname,UserName,Email,TsRoles.ToList<String>());
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    ctx.TsUsers.Add(newTsUser);
                    ctx.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al crear un nuevo usuario: " + UserName, ex);
            }   
        }

        public MembershipUserCollection GetAllUsers()
        {
            return Membership.GetAllUsers();
        }

        public string[] GetRoles()
        {
            return Roles.GetAllRoles();
        }

        public string[] GetUserRoles(String UserName)
        {
            return Roles.GetRolesForUser(UserName);
        }

        public TsUser GetUser(String UserName)
        {
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    TsUser tu = (from u in ctx.TsUsers
                             where u.UserName == UserName
                             select u).SingleOrDefault();
                    return tu;
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener un Usuario: " + UserName, ex);
                throw ex;
            }   
        }

        public void UpdateUser(TsUser UpdatedUser, List<String> RolList)
        {
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    ctx.TsUsers.Attach(UpdatedUser);
                    ctx.Entry(UpdatedUser).State = EntityState.Modified;
                    ctx.SaveChanges();
                }

                MembershipUser editedUser = Membership.GetUser(UpdatedUser.UserName);
                editedUser.Email = UpdatedUser.Email;
                Membership.UpdateUser(editedUser);
                string[] oldRoles = Roles.GetRolesForUser(UpdatedUser.UserName);
                Roles.RemoveUserFromRoles(UpdatedUser.UserName, oldRoles);
                Roles.AddUserToRoles(UpdatedUser.UserName, RolList.ToArray());
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al actualizar el Usuario", ex);
            } 
        }

        public void RemoveUser(String UserName)
        {
            TsUser UserToDelete = GetUser(UserName);
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    ctx.TsUsers.Attach(UserToDelete);
                    ctx.TsUsers.Remove(UserToDelete);
                    ctx.SaveChanges();

                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al eliminar un Usuario", ex);
            } 
        }

        public List<TsUser> GetUsersForTeam(Team team)
        {
            List<TsUser> toReturn = new List<TsUser>();
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    var allUsers = (from u in ctx.TsUsers.Include("Favorites")
                                    select u);

                    foreach (TsUser auxUser in allUsers)
                    {
                        if (auxUser.Favorites != null && auxUser.Favorites.Contains(team))
                        {
                            toReturn.Add(auxUser);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error obtener los Usuario para un Equipo", ex);
            }
            return toReturn;
        }

        public void FollowTeam(String UserName, Team TeamToFollow)
        {
            TsUser UpdatedUser = GetUser(UserName);
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    ctx.TsUsers.Attach(UpdatedUser);
                    ctx.Teams.Attach(TeamToFollow);
                    UpdatedUser.Favorites.Add(TeamToFollow);
                    ctx.Entry(UpdatedUser).State = EntityState.Modified;
                    ctx.SaveChanges();

                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al intentar seguir a un Equipo", ex);
            }   
        }

        public TsUser GetFullUserData(String UserName)
        {
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    TsUser tu = (from u in ctx.TsUsers.Include("Favorites")
                                 where u.UserName == UserName
                                 select u).SingleOrDefault();
                    return tu;
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener los datos completos de un Usuario" + UserName, ex);
                return null;
            }   
        }

        public List<Team> GetFavoriteTeamsForUser(TsUser user)
        {
            List<Team> userTeams = new List<Team>();
            
            foreach (Team auxTeam in TsSystem.Instance.GetAllTeamsWithFollowers())
            {
                foreach (TsUser follower in auxTeam.Followers)
                {
                    if (follower.TsUserId == user.TsUserId)
                    {
                        userTeams.Add(auxTeam);
                    }
                }
            }
            return userTeams;
        }
    }
}
